package com.secure.config;

import com.secure.handler.EncryptDecryptHandler;
import com.secure.handler.RsaEncryptDecryptHandler;
import com.secure.handler.RsaSignatureHandler;
import com.secure.handler.SignatureHandler;
import com.secure.properties.SecureClientProperties;
import com.secure.support.feign.FeignRequestSecureInterceptor;
import com.secure.support.feign.FeignResponseDecryptDecoder;
import com.secure.support.resttemplate.RestRequestSecureInterceptor;
import feign.Feign;
import feign.RequestInterceptor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
import org.springframework.boot.context.event.ApplicationPreparedEvent;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.cloud.openfeign.support.HttpMessageConverterCustomizer;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpRequest;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.web.client.RestOperations;
import org.springframework.web.client.RestTemplate;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.List;

/**
 * API安全客户端配置
 *
 * @author duchao
 */
@Slf4j
@Configuration(proxyBeanMethods = false)
@ConditionalOnWebApplication
@EnableConfigurationProperties({SecureClientProperties.class})
public class ApiSecureClientAutoConfiguration {

    @Bean
    @ConditionalOnMissingBean
    public EncryptDecryptHandler encryptDecryptHandler() {
        return new RsaEncryptDecryptHandler();
    }

    @Bean
    @ConditionalOnMissingBean
    public SignatureHandler signatureHandler() {
        return new RsaSignatureHandler();
    }

    /**
     * feign配置
     *
     * @author duchao
     */
    @Configuration(proxyBeanMethods = false)
    @ConditionalOnClass(Feign.class)
    public static class FeignConfig {

        @Bean
        public RequestInterceptor feignRequestSecureInterceptor(SecureClientProperties secureClientProperties, SignatureHandler signatureHandler, EncryptDecryptHandler encryptDecryptHandler) {
            return new FeignRequestSecureInterceptor(secureClientProperties, signatureHandler, encryptDecryptHandler);
        }

        @Bean
        public FeignResponseDecryptDecoder feignResponseDecryptDecoder(ObjectFactory<HttpMessageConverters> messageConverters,
                                                                       ObjectProvider<HttpMessageConverterCustomizer> customizers,
                                                                       SecureClientProperties secureClientProperties,
                                                                       EncryptDecryptHandler encryptDecryptHandler) {
            return new FeignResponseDecryptDecoder(messageConverters, customizers, secureClientProperties, encryptDecryptHandler);
        }
    }

    /**
     * restTemplate配置
     *
     * 含有请求头ApiSecure，表示安全请求
     *
     * @author duchao
     */
    @Configuration(proxyBeanMethods = false)
    @ConditionalOnClass(RestOperations.class)
    public static class RestTemplateConfig {

        @Bean("secureRestTemplate")
        @ConditionalOnMissingBean(RestTemplate.class)
        public RestTemplate secureRestTemplate(){
            return new RestTemplate();
        }

        @Bean
        public ApplicationListener<ApplicationPreparedEvent> applicationListener(RestTemplate restTemplate,SecureClientProperties secureClientProperties,SignatureHandler signatureHandler,EncryptDecryptHandler encryptDecryptHandler){
            List<HttpMessageConverter<?>> messageConverters = restTemplate.getMessageConverters();
            for (int i = 0; i < messageConverters.size(); i++) {
                HttpMessageConverter<?> httpMessageConverter = messageConverters.get(i);
                if (httpMessageConverter.getClass().equals(StringHttpMessageConverter.class)) {
                    messageConverters.set(i, new StringHttpMessageConverter(StandardCharsets.UTF_8));
                }
            }
            return event -> restTemplate.getInterceptors().add(new RestRequestSecureInterceptor(secureClientProperties, signatureHandler, encryptDecryptHandler));
        }
    }

}

